package top.xlq.mydb.backend.dm.page;

import top.xlq.mydb.backend.dm.pageCache.PageCache;
import top.xlq.mydb.backend.parser.Parser;

import java.util.Arrays;

/**
 * PageX管理普通页
 * 普通页结构
 * [FreeSpaceOffset] [Data]
 * FreeSpaceOffset: 2字节 空闲位置开始偏移
 */
public class PageX {
    private static final short OF_FREE = 0;// 空闲位置偏移开始位置
    private static final short OF_DATA = 2;// 空闲位置偏移数据的大小-2字节
    public static final int MAX_FREE_SPACE = PageCache.PAGE_SIZE - OF_DATA;//最大空闲空间

    // 获取pg的FSO
    public static short getFSO(Page page) {
        return getFSO(page.getData());
    }

    private static short getFSO(byte[] raw) {
        return Parser.parserShort(Arrays.copyOfRange(raw, 0, 2));
    }

    // 设置pg的FSO
    public static void setFSO(byte[] raw, short ofData) {
        System.arraycopy(Parser.parserShort2Byte(ofData),0,raw,0,2);
    }

    // 获取页面的空闲空间大小
    public static int getFreeSpace(Page pg) {
        return PageCache.PAGE_SIZE - (int)getFSO(pg.getData());
    }

    // 将 raw 插入 pg 中，返回插入位置
    public static short insert(Page pg,byte[] raw){
        pg.setDirty(true);// 将pg的dirty标志设置为true，表示pg的数据已经被修改
        // 更改数据
        short fso = getFSO(pg);// 获取pg的空闲空间偏移量
        System.arraycopy(raw,0,pg.getData(),fso,raw.length);
        // 更改fso
        setFSO(pg.getData(), (short) (fso + raw.length));
        return fso;
    }

    /**
     * 用于数据库崩溃之后的数据插入恢复
     * @param pg 页面
     * @param raw 数据
     * @param offset 插入前的offset
     */
    // 将 raw 插入 pg 中的 offset 位置，并将 pg 的 offset 设置为较大的 offset
    public static void recoverInsert(Page pg, byte[] raw, short offset) {
        pg.setDirty(true);
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length);

        short rawFSO = getFSO(pg.getData());
        if(rawFSO < offset + raw.length) {// 比较 插入数据之后的空闲位置偏移量 和 数据库崩溃之后这个页面本身的空闲偏移量
            setFSO(pg.getData(), (short)(offset+raw.length));
        }
    }
    /**
     * 用于数据库崩溃之后的数据修改恢复
     * @param pg 页面
     * @param raw 数据
     * @param offset 插入前的offset
     */
    // 将 raw 插入 pg 中的 offset 位置，不更新 update
    public static void recoverUpdate(Page pg, byte[] raw, short offset) {
        pg.setDirty(true);
        System.arraycopy(raw, 0, pg.getData(), offset, raw.length);
    }
}
